import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;

import agentFramework.action.Action;
import agentFramework.agent.Agent;
import agentFramework.core.Core;
import agentFramework.core.env.Environment;
import agentFramework.strategy.EpsQLStrategy;
import agentFramework.strategy.QLStrategy;
import agentFramework.strategy.Strategy;
import agentFramework.tools.LeaderDetector;


public class IrishEnvironment extends Environment	
{

	public IrishEnvironment(String configFile) 
	{
		super(configFile);
		
		// add the possible actions
		this.addPossibleAction(new IrishAction(IrishAction.TYPE_GO_TO_THE_PUB));
		this.addPossibleAction(new IrishAction(IrishAction.TYPE_STAY_HOME));
	}

	@Override
	public double computeReward(Agent a) 
	{
		int 		drinkers = 0;
		double 		reward;

		for (Agent agent : this.getAgentList())
		{
			if (agent.getCurrentAction().getType() == IrishAction.TYPE_GO_TO_THE_PUB)
			{
				drinkers++;
			}
		}

		reward = (drinkers * 1.0 / this.getAgentCount() < 0.5) ? 1.0 : -1.0;
		
		if (a.getCurrentAction().getType() == IrishAction.TYPE_STAY_HOME)
		{
			reward = -reward;
		}

		return reward;
	}

	@Override
	public void loadFromFile(String configFile) 
	{
		BufferedReader  br = null;
		String			line = null;
		StringTokenizer st = null;
		int 			nAgents;
		int 			nBully;
		int				nQL;
		int				nEpsQL;
		int				nEdges;
		int				nIterations;
		int 			nEpochs;
		int				PHI;
		int				PI;
		double			SIGMA;
		double			RHO;
		boolean			edge[][] = null;
		
		try
		{
			br = new BufferedReader(new FileReader(configFile));
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			nAgents = Integer.parseInt(st.nextToken());
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			
			for (int i = 0; i < nAgents; i++)
			{
				int 			type = Integer.parseInt(st.nextToken());
				Agent 			a = new IrishGuy(i, Core.id, this);
				Strategy		strategy = null;
				
				switch (type)
				{
					case Constants.TYPE_BULLY:
					{
						strategy = new IrishBullyStrategy(this, a);
						break;
					}
					
					case Constants.TYPE_QL:
					{
						strategy = new QLStrategy(this, a, Constants.QL_ALPHA, Constants.QL_DEFAULT_PENALTY);
						break;
					}
					
					case Constants.TYPE_EPS_QL:
					{
						strategy = new EpsQLStrategy(this, a, Constants.QL_EPSILON, Constants.QL_ALPHA, Constants.QL_DEFAULT_PENALTY);
						break;
					}
					
					default: break;
				}

				a.setStrategy(strategy);
				this.addAgent(a);
			}
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			nEdges 	= Integer.parseInt(st.nextToken());
			
			line 		= br.readLine();
			st 			= new StringTokenizer(line);
			nIterations = Integer.parseInt(st.nextToken());
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			nEpochs = Integer.parseInt(st.nextToken());
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			PHI 	= Integer.parseInt(st.nextToken());
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			PI 		= Integer.parseInt(st.nextToken());
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			SIGMA 	= Double.parseDouble(st.nextToken());
			
			line 	= br.readLine();
			st 		= new StringTokenizer(line);
			RHO 	= Double.parseDouble(st.nextToken());
			
			edge = new boolean[nEdges][nEdges];
			
			for (boolean[] row : edge)
			{
				Arrays.fill(row, false);
			}
			
			for (int i = 0; i < nEdges; i++)
			{
				int u, v;
				
				line = br.readLine();
				st = new StringTokenizer(line);
				u = Integer.parseInt(st.nextToken());
				v = Integer.parseInt(st.nextToken());
				
				edge[u][v] = edge[v][u] = true;
			}
			
			this.addNeighborMatrix(edge);
			this.addCore(new IrishCore(this, nIterations, nEpochs));
			
			LeaderDetector ld = new LeaderDetector(nAgents, edge, PHI, PI, SIGMA, RHO);
			((IrishCore) this.getCore()).setLeaderDetector(ld);
			
			br.close();
		}
		catch(IOException e) {e.printStackTrace();}
	}
}
